#include "types.h"
#include "stat.h"
#include "user.h"
#include "signal.h"
#include "fssp.h"
#include "barrier.c"

char printstates[7] = {'Q', 'P', 'R', 'Z', 'M', 'F' ,'X'};

soldier_state transitionFunction[5][5][5] = {
		{{Q,P,Q,Q,0},{P,P, 0, 0},{Q,0,Q,0,0},{Q,0,0,Q,0},{0,0,0,0,0}},//state Q transition table
		{{Z,Z,R,R,0},{Z,0,Z,Z,0},{R,Z,Z,0,0},{R,Z,0,Z,0},{0,0,0,0,0}},//state P transition table
		{{0,0,R,P,Z},{0,0,M,R,M},{R,M,0,0,M},{P,R,0,0,R},{Z,M,M,R,M}},//state R transition table
		{{0,0,Q,P,Q},{0,Z,0,Z,0},{Q,0,Q,Q,0},{P,Z,Q,F,Q},{Q,0,0,Q,Q}},//state Z transition table
		{{0,0,0,0,0},{0,0,0,0,0},{0,0,R,Z,0},{0,0,Z,0,0},{0,0,0,0,0}}//state M transition table

};

soldier_state generalTransitionFunction[5][5] = {
		{Q,P,Q,Q,0},//state Q
		{Z,0,Z,Z,0},//state P
		{0,0,0,0,0},//state R
		{0,Z,Q,F,Q},//state Z
		{0,0,0,0,0}//state M

};

soldier_state rightmostSoldierTransitionFunction[5][5] = {
		{Q,P,0,Q,0},//state Q
		{0,0,Z,Z,0},//state F
		{0,0,0,0,0},//state R
		{0,0,Q,F,Q},//state Z
		{0,0,0,0,0}//state M

};

int allReady()
{
      int i=0;
      for(i=0;i<num_soldiers;i++)
      {
        if(states[i] != F)
             return 0;
      }
      return 1;
}

void printStates()
{
  int i;
      for(i=0;i<num_soldiers;i++)
      {
        printf(1,"%c ",printstates[states[i]]);
      }
      printf(1,"\n");
}

soldier_state findNextState(struct soldier* s)
{

  soldier_state left_state,right_state;

  //read the state of the soldier to your left:
  if(s->id)
           left_state = states[(s->id)-1];
  else          // general
           left_state = X;
  //read the state of the soldier to your right:
  if((s->id+1)<num_soldiers)
           right_state = states[(s->id)+1];
  else          // rightmost soldier
           right_state = X;

  if(right_state != X && left_state != X)
        return transitionFunction[s->state][left_state][right_state];

  if (left_state==X)
        return generalTransitionFunction[s->state][right_state];
  if (right_state==X)
        return rightmostSoldierTransitionFunction[s->state][left_state];
  return 0;
}

void soldierStep(void* soldier)
{
   struct soldier* s = (struct soldier*)soldier;
   while(!allReady())
  {

	  s->state=findNextState(s);
      barrier_pass(s->bar);
      states[s->id] = s->state;
      barrier_pass(s->bar);
  }
}

int main(int argc, char *argv[])
{
  num_soldiers = atoi(argv[1]);
  int i;
  struct barrier* bar;

  struct soldier* soldiers[num_soldiers];
  states = malloc(sizeof(soldier_state)*num_soldiers);
  for(i=0;i<num_soldiers;i++)
  {
      soldiers[i] = malloc(sizeof(struct soldier));
  }

  //initialize the  general
  soldiers[0]->state = P;
  states[0] = P;

  //and the rest of the soldiers
  for(i=1;i<num_soldiers;i++)
  {
      soldiers[i]->state = Q;
      states[i] = Q;
  }



  bar = malloc(sizeof(struct barrier));
  barrier_init(bar,num_soldiers + 1);

  uthread_init();

  for(i=0;i<num_soldiers;i++)
  {
      soldiers[i]->bar = bar;
      soldiers[i]->id = uthread_create(soldierStep,soldiers[i]) - 1;
  }

  while(!allReady())
  {
      printStates();
      barrier_pass(bar);
      barrier_pass(bar);
  }
  printStates();

  exit();
}
